package cn.zoujiedev.netty.core.handler;

import cn.zoujiedev.netty.core.bean.Header;
import cn.zoujiedev.netty.core.bean.MessageType;
import cn.zoujiedev.netty.core.bean.NettyMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Classname HeartbeatReqHandler
 * @Description
 * @Date 2022-11-3 16:35
 * @Created by zoujie
 */
@Slf4j
public class HeartbeatReqHandler extends ChannelInboundHandlerAdapter {

  private ScheduledFuture<?> scheduledFuture;

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    ctx.writeAndFlush(buildReqMessage());
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    NettyMessage message = (NettyMessage) msg;

    //如果是握手回复消息
    Header header = message.getHeader();
    if(header != null && header.getType() == MessageType.HAND_SHAKE_RESPONSE){
      // TODO: 2022-11-3 是否判断登录成功
      scheduledFuture = ctx.executor()
          .scheduleAtFixedRate(new HeartbeatTask(ctx), 0, 5, TimeUnit.SECONDS);

    }else if(header != null && header.getType() == MessageType.HEARTBEAT_RESPONSE){
      //如果是心跳回复
      log.info("Client receive server heartbeat message : ---> {}",message);
    }else {
      ctx.fireChannelRead(msg);
    }
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    boolean cancel = scheduledFuture.cancel(true);
    log.error("Heartbeat send error, cancel the heartbeat task, cancel result: {}",cancel);
    ctx.fireExceptionCaught(cause);
  }

  private NettyMessage buildReqMessage(){
    NettyMessage message = new NettyMessage();

    Header h = new Header();
    h.setType(MessageType.HEARTBEAT_REQUEST);

    message.setHeader(h);
    return message;
  }

  private class HeartbeatTask implements Runnable{

    private final ChannelHandlerContext ctx;

    private final Logger log = LoggerFactory.getLogger(HeartbeatTask.class);

    public HeartbeatTask(ChannelHandlerContext ctx){
      this.ctx = ctx;
    }

    @Override
    public void run() {
      NettyMessage msg = buildReqMessage();
      ctx.writeAndFlush(msg);
      log.info("Client send heartbeat message to server: ---> {}",msg);
    }

    private NettyMessage buildHeartbeatReq(){
      NettyMessage message = new NettyMessage();

      Header h = new Header();
      h.setType(MessageType.HEARTBEAT_REQUEST);

      message.setHeader(h);
      return message;
    }
  }
}
